<?php

class config
{
	public static $itemDir = '/share/Torrents/Inbox';
	public static $tagDir = '/share/Torrents/Tagged';
	
	public static $blacklistedFolderPrefixes = array('.', ':');
	public static $blacklistedFolders = array('Network Trash Folder', 'Temporary Items');
}

class folder
{
	protected $name;
	protected $path;
	
	function __construct($name, $path)
	{
		$this->name = $name;
		$this->path = $path;
	}
	
	function getName()
	{
		return $this->name;
	}
	
	function setName($name)
	{
		$this->name = $name;
	}

	function getPath()
	{
		return $this->path;
	}
	
	function isLink()
	{
		return is_link($this->path);
	}
}

class tag extends folder
{
	
}

class resultObject
{
	var $value;
	var $message;

	function __construct($value, $message="")
	{
		$this->value = $value;
		$this->message = $message;
	}
}

class util
{
	public static function getRelativePath($sourcePath, $targetPath)
	{
		$spArr = split("/", $sourcePath);
		$tpArr = split("/", $targetPath);
		
		$up = "";
		$dn = "";

		$equal = true;

		for ($i=0; $i<max(count($spArr), count($tpArr)); $i++)
		{	
			if (!$equal || $spArr[$i] != $tpArr[$i])
			{
				$equal = false;
				
				if (!empty($spArr[$i]))
				{
					$up .= "../";
				}
				
				if (!empty($tpArr[$i]))
				{
					$dn .= $tpArr[$i];
				}
				
				if (!empty($tpArr[$i+1]))
				{
					$dn .= "/";
				}
			}
		}
		
		return $up . $dn;
	}
	
	protected static function getItemsInPath($path)
	{
		$result = array();

		$itemList = @scandir(stripslashes($path));
		
		if ($itemList === false)
		{
			return false;
		}
		
		foreach ($itemList as $item)
		{
			$validFolder = true;
					
			foreach (config::$blacklistedFolders as $folder)
			{
				if ($item == $folder)
				{
					$validFolder = false;
				}
			}
			
			foreach (config::$blacklistedFolderPrefixes as $prefix)
			{
				if (substr($item, 0, count($prefix)) == $prefix)
				{
					$validFolder = false;
				}
			}
					
			if (!$validFolder)
			{
				continue;
			}

			$itemPath = "$path/$item";
			$itemName = htmlspecialchars($item);

			$folder = new folder($itemName, $itemPath);
			array_push($result, $folder);
		}

		return $result;
		
	}
	
	protected static function createFolderInPath($path, $name)
	{
		$result = true;
		$message = "";
	
		$folderPath = stripslashes("$path/$name");

		if (empty($name))
		{
			$result = false;
			$message = "No folder name given!";
		}
		elseif (!is_dir($folderPath))
		{
			$result = mkdir($folderPath, 0777);
			
			if ($result)
			{
				$message = "Folder created successfully!";
			}
			else
			{
				$message = "Failed creating folder '$name'!";
			}
		}
		else
		{
			$result = false;
			$message = "Folder '$name' already exists!";
		}
		
		return new resultObject($result, $message);
	}

	protected static function removeFolderInPath($path, $name)
	{
		$result = true;
		$message = "";
	
		$folderPath = "$path/$name";

		if (empty($name))
		{
			$result = false;
			$message = "No folder name given!";
		}
		elseif (is_dir($folderPath))
		{
			$result = rmdir($folderPath);
			
			if ($result)
			{
				$message = "Folder removed successfully!";
			}
			else
			{
				$message = "Failed removing folder '$name'!";
			}
		}
		else
		{
			$result = false;
			$message = "Folder '$name' didn't exists!";
		}
		
		return new resultObject($result, $message);
	}

	protected static function createSymlinkInPath($sourcePath, $sourceName, $targetPath, $targetName)
	{
		$result = true;
		$message = "";
	
		$target = util::getRelativePath($sourcePath, "$targetPath/$targetName");

		// return new resultObject(false, $target);

		chdir($sourcePath);

		if (empty($sourceName))
		{
			$result = false;
			$message = "No link name given!";
		}
		// elseif (!is_dir($sourceName) && is_dir($target))
		// {
			$result = @symlink($target, $sourceName);
			
			if ($result)
			{
				$message = "Link created successfully!";
			}
			else
			{
				$message = "Failed creating link '$sourceName'!";
			}
		// }
		// elseif (!is_dir($target))
		// {
		// 	$result = false;
		// 	$message = "(sourcePath = '$sourcePath') Target '$targetName' doesn't exist!";
		// }
		// elseif (is_dir($sourceName))
		// {
		// 	$result = false;
		// 	$message = "Link '$sourceName' already exists!";
		// }
		// else
		// {
		// 	$result = false;
		// 	$message = "Undefined error occurred!";
		// }
		
		return new resultObject($result, $message);
	}

	protected static function removeSymlinkInPath($sourcePath, $sourceName)
	{
		$result = true;
		$message = "";
	
		chdir($sourcePath);

		if (empty($sourceName))
		{
			$result = false;
			$message = "No link name given!";
		}
		// elseif (is_dir($sourceName))
		// {
			$result = @unlink($sourceName);
			
			if ($result)
			{
				$message = "Link removed successfully!";
			}
			else
			{
				$message = "Failed removing link '$sourceName'!";
			}
		// }
		// elseif (!is_dir($sourceName))
		// {
		// 	$result = false;
		// 	$message = "Link '$sourcePath$sourceName' doesn't exist!";
		// }
		// else
		// {
		// 	$result = false;
		// 	$message = "Undefined error occurred!";
		// }
		
		return new resultObject($result, $message);
	}
	
	public static function getTagFolders($tag="")
	{
		$path = (!empty($tag))? config::$tagDir . "/" . stripslashes($tag) : config::$tagDir;

		$items = util::getItemsInPath($path);

		if (!empty($tag))
		{
			foreach ($items as $item)
			{
				$name = stripslashes($tag) . "/" . $item->getName();
				
				$item->setName($name);
			}
		}

		return $items;
	}

	public static function getItems()
	{
		return util::getItemsInPath(config::$itemDir);
	}

	public static function getItemsInTagFolder($tag)
	{
		return util::getItemsInPath(config::$tagDir . "/" . stripslashes($tag));
	}
	
	public static function createTagFolder($name, $scope)
	{
		$path = (isset($scope))? config::$tagDir . "/" . $scope : config::$tagDir;
		
		return util::createFolderInPath($path, $name);
	}

	public static function removeTagFolder($name, $scope)
	{
		$path = (isset($scope))? config::$tagDir . "/" . $scope : config::$tagDir;

		return util::removeFolderInPath($path, stripslashes($name));
	}

	public static function createSymlink($tagName, $itemName)
	{
		return util::createSymlinkInPath(config::$tagDir . "/" . $tagName, $itemName, config::$itemDir, $itemName);
	}
	
	public static function removeSymlink($tagName, $itemName)
	{
		return util::removeSymlinkInPath(config::$tagDir . "/" . $tagName, $itemName);
	}
}

class controller
{
	function getTags($tag="")
	{
		$result = array();

		$items = util::getTagFolders($tag);
		
		foreach($items as $item)
		{
			$match = false;

			if (!$item->isLink())
			{
				$match = true;
			}

			if ($match)
			{
				array_push($result, $item);
			}
		}

		return $result;
	}
	
	function getTagsRecursive($tag="")
	{
		$result = array();
		
		$items = $this->getTags($tag);
		
		foreach($items as $item)
		{
			$result[] = $item;
			
			$path = $this->getTagsRecursive($item->getName());
			
			$result = array_merge($result, $path);
		}
		
		return $result;
	}

	function getTagPath($tag)
	{
		return (isset($_GET["tag"]))? $_GET["tag"] . "/" . $tag : $tag;
	}

	function tagItem($tagName, $itemName)
	{
		return util::createSymlink(stripslashes($tagName), stripslashes($itemName));
	}
	
	function untagItem($tagName, $itemName)
	{
		return util::removeSymlink(stripslashes($tagName), stripslashes($itemName));
	}

	function getItems()
	{
		return util::getItems();
	}

	function getItemsInTag($tag, $sourceItems=array())
	{
		$result = array();
		
		$items = (count($sourceItems) < 1) ? util::getItems() : $sourceItems;

		$tagItems = util::getItemsInTagFolder($tag);
		
		foreach ($items as $item)
		{
			$match = false;
			
			foreach($tagItems as $tagItem)
			{
				if ($tagItem->getName() == $item->getName())
				{
					$match = true;
				}
			}
			
			if ($match)
			{
				array_push($result, $item);
			}
		}
		
		return $result;
	}

	function getItemsInTags($tags, $sourceItems=array())
	{
		$result = (count($sourceItems) < 1) ? util::getItems() : $sourceItems;
		
		foreach($tags as $tag)
		{
			$result = $this->getItemsInTag($tag, $result);
		}
		
		return $result;
	}

	function getItemsOutsideTag($tag, $sourceItems=array())
	{
		$result = array();
		
		$items = $sourceItems;

		$tagItems = util::getItemsInTagFolder($tag);
		
		foreach ($items as $item)
		{
			$match = false;

			foreach($tagItems as $tagItem)
			{
				if ($tagItem->getName() == $item->getName())
				{
					$match = true;
				}
			}
			
			if (!$match)
			{				
				array_push($result, $item);
			}
		}
		
		return $result;
	}

	function getItemsOutsideTags($tags)
	{
		$result = util::getItems();
		
		foreach($tags as $tag)
		{
			$result = $this->getItemsOutsideTag($tag, $result);
		}
		
		return $result;
	}

	function getUntaggedItems()
	{
		$tags = array();
		
		foreach($this->getTagsRecursive() as $tag)
		{
			$tags[] = $tag->getName();
		}
		
		return $this->getItemsOutsideTags($tags);
	}

	function createTag($name, $scope)
	{
		return util::createTagFolder($name, $scope);
	}

	function removeTag($name, $scope)
	{
		return util::removeTagFolder($name, $scope);
	}
}

?>